﻿using JESAI.Redis.Abstracts;
using JESAI.Redis.Abstracts.RedisClients;
using JESAI.Redis.Builders;
using JESAI.Redis.Enums;
using JESAI.Redis.Helpers;
using JESAI.Redis.Internal.Status;
using JESAI.Redis.Messages;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace JESAI.Redis.RedisClients
{
    public class RedisClientFactory : IRedisClientFactory
    {
        private IConnectionBuilder _connectionBuilder;
        public RedisClientFactory(IConnectionBuilder connectionBuilder)
        {
            _connectionBuilder = connectionBuilder;
        }
        public static async Task<RedisClientFactory> BuildAsync(IConnectionBuilder connectionBuilder)
        {
            var factory = new RedisClientFactory(connectionBuilder);
            await RedisClientConnectionStateManager.InitAsync(connectionBuilder.ConnectionStringArray);
            return factory;
        }

        public async Task<IRedisClient> GetAsync(Action<IRedisClient> disposeTask, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();
            var client = _connectionBuilder.ServerType switch
            {
                ServerType.Sentinel => await CreateSentinelClient(disposeTask, cancellationToken),
                ServerType.Cluster => await CreateClusterClient(disposeTask, cancellationToken),
                _ => await CreateSimpleClient(disposeTask, cancellationToken)
            };

            return client;
        }

        private async Task<IRedisClient> CreateSimpleClient(Action<IRedisClient> disposeTask, CancellationToken cancellationToken = default)
        {
            var connectionInfo = await GetConnectionInfo(cancellationToken);

            return new RedisClient(connectionInfo.key, connectionInfo.tcpClient, _connectionBuilder, connectionInfo.redisHost, connectionInfo.port, disposeTask);
        }

        private async Task<IRedisClient> CreateSentinelClient(Action<IRedisClient> disposeTask, CancellationToken cancellationToken = default)
        {

            return null;
        }

        private async Task<IRedisClient> CreateClusterClient(Action<IRedisClient> disposeTask, CancellationToken cancellationToken = default)
        {

            return null;
        }
        /// <summary>
        /// 获取连接信息
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private async Task<(string key, TcpClient tcpClient, string redisHost, int port)> GetConnectionInfo(
            CancellationToken cancellationToken)
        {
            var hostInfo = RedisClientConnectionStateManager.Get();
            //初始化tcp客户端
            var tcpClient = new TcpClient()
            {
                ReceiveTimeout = _connectionBuilder.TimeOut,
                SendTimeout = _connectionBuilder.TimeOut
            };

            //获取ip地址
            if (!IPAddress.TryParse(hostInfo.redisHost.Host, out var ips))
            {
                ips = (await Dns.GetHostAddressesAsync(hostInfo.redisHost.Host)).FirstOrDefault();
            }

            //todo 增加连接拒绝的处理，拒绝后就直接 将当前主机信息填写进 失败数据中，然后后台服务检测 是否恢复
            await tcpClient.ConnectAsync(ips, hostInfo.redisHost.Port);

            //todo ipv6
            return (hostInfo.key, tcpClient, ips.MapToIPv4().ToString(), hostInfo.redisHost.Port);
        }
    }
}
